﻿/******************************************************************************************************
Copyright (c) 2014 Steven Giacomelli (stevegiacomelli@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************************************/

using System;

namespace SharpGeo
{
    /// <summary>
    /// This class represents a unit of measurement represented by readonly static types
    /// </summary>
    sealed public class Unit
    {
        #region Constructor

        /// <summary>
        /// The default private constructor
        /// </summary>
        private Unit()
        {
        }

        #endregion Constructor

        #region Properties

        /// <summary>
        /// The type of unit of measurement
        /// </summary>
        public UnitType UnitType { get; private set; }

        /// <summary>
        /// The name of the unit
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// The common abreviation of the unit
        /// </summary>
        public string Abbreviation { get; private set; }

        /// <summary>
        /// Returns true if this is a base unit
        /// </summary>
        public bool BaseUnit { get { return BaseConversionFactor == 1; } }

        /// <summary>
        /// The conversion factor to the base unit
        /// </summary>
        public double BaseConversionFactor { get; private set; }

        #endregion Properties

        #region Consts

        /// <summary>
        /// The conversion factor to convert Degrees to Radians
        /// </summary>
        public const double DegreesToRadians = Math.PI / 180D;

        /// <summary>
        /// The conversion factor to convert Radians to Degrees
        /// </summary>
        public const double RadiansToDegrees = 180D / Math.PI;

        #endregion Consts

        #region Angular Units

        /// <summary>
        /// A unit describing a radian unit of measurement (the base unit for angular measurements)
        /// </summary>
        public static readonly Unit Radians = new Unit()
        {
            UnitType = UnitType.Angular,
            Name = Properties.Resources.UnitsRadian,
            Abbreviation = "rad",
            BaseConversionFactor = 1
        };

        /// <summary>
        /// A unit describing a degree unit of measurement
        /// </summary>
        public static readonly Unit Degrees = new Unit()
        {
            UnitType = UnitType.Angular,
            Name = Properties.Resources.UnitsDegree,
            Abbreviation = "\xb0",
            BaseConversionFactor = Math.PI / 180.0
        };

        /// <summary>
        /// A unit describing an arc minute unit of measurement
        /// </summary>
        public static readonly Unit ArcMinute = new Unit()
        {
            UnitType = UnitType.Angular,
            Name = Properties.Resources.UnitsArcMinute,
            Abbreviation = "min",
            BaseConversionFactor = 60 / (Math.PI / 180.0)
        };

        /// <summary>
        /// A unit describing an arc second unit of measurement
        /// </summary>
        public static readonly Unit ArcSecond = new Unit()
        {
            UnitType = UnitType.Angular,
            Name = Properties.Resources.UnitsArcSecond,
            Abbreviation = "sec",
            BaseConversionFactor = 3600 / (Math.PI / 180.0)
        };

        #endregion Angular Units

        #region Metric Linear

        /// <summary>
        /// A unit describing a kilometer unit of measurement
        /// </summary>
        public static readonly Unit Kilometer = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsKilometer,
            Abbreviation = "km",
            BaseConversionFactor = 1000
        };

        /// <summary>
        /// A unit describing a meter unit of measurement (the base unit for linear measurements)
        /// </summary>
        public static readonly Unit Meter = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsMeter,
            Abbreviation = "m",
            BaseConversionFactor = 1
        };

        /// <summary>
        /// A unit describing a decimeter unit of measurement
        /// </summary>
        public static readonly Unit Decimeter = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsDecimeter,
            Abbreviation = "dm",
            BaseConversionFactor = 1 / 10
        };

        /// <summary>
        /// A unit describing a centimeter unit of measurement
        /// </summary>
        public static readonly Unit Centimeter = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsCentimeter,
            Abbreviation = "cm",
            BaseConversionFactor = 1 / 100
        };

        /// <summary>
        /// A unit describing a millimeter unit of measurement
        /// </summary>
        public static readonly Unit Millimeter = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsMillimeter,
            Abbreviation = "mm",
            BaseConversionFactor = 1 / 1000
        };

        #endregion Metric Linear

        #region International Linear

        /// <summary>
        /// A unit describing a nautical mile unit of measurement
        /// </summary>
        public static readonly Unit NauticalMile = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsNauticalMile,
            Abbreviation = "kmi",
            BaseConversionFactor = 1852.0
        };

        /// <summary>
        /// A unit describing an inch unit of measurement
        /// </summary>
        public static readonly Unit Inch = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsInch,
            Abbreviation = "in",
            BaseConversionFactor = 0.0254
        };

        /// <summary>
        /// A unit describing a foot unit of measurement
        /// </summary>
        public static readonly Unit Foot = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsFoot,
            Abbreviation = "ft",
            BaseConversionFactor = 0.3048
        };

        /// <summary>
        /// A unit describing a yard unit of measurement
        /// </summary>
        public static readonly Unit Yard = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsYard,
            Abbreviation = "yd",
            BaseConversionFactor = 0.9144
        };

        /// <summary>
        /// A unit describing a statue mile unit of measurement
        /// </summary>
        public static readonly Unit StatuteMile = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsStatuteMile,
            Abbreviation = "mi",
            BaseConversionFactor = 1609.344
        };

        /// <summary>
        /// A unit describing a fathom unit of measurement
        /// </summary>
        public static readonly Unit Fathom = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsFathom,
            Abbreviation = "fath",
            BaseConversionFactor = 1.8288
        };

        /// <summary>
        /// A unit describing a chain unit of measurement
        /// </summary>
        public static readonly Unit Chain = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsChain,
            Abbreviation = "ch",
            BaseConversionFactor = 20.1168
        };

        /// <summary>
        /// A unit describing a link unit of measurement
        /// </summary>
        public static readonly Unit Link = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsLink,
            Abbreviation = "link",
            BaseConversionFactor = 0.201168
        };

        #endregion International Linear

        #region US Linear

        /// <summary>
        /// A unit describing a US Surveyor's inch unit of measurement
        /// </summary>
        public static readonly Unit USInch = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsUSInch,
            Abbreviation = "us-in",
            BaseConversionFactor = 1 / 39.37
        };

        /// <summary>
        /// A unit describing a US Surveyor's foot unit of measurement
        /// </summary>
        public static readonly Unit USFoot = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsUSFoot,
            Abbreviation = "us-ft",
            BaseConversionFactor = 0.304800609601219
        };

        /// <summary>
        /// A unit describing a US Surveyor's yard unit of measurement
        /// </summary>
        public static readonly Unit USYard = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsUSYard,
            Abbreviation = "us-yd",
            BaseConversionFactor = 0.914401828803658
        };

        /// <summary>
        /// A unit describing a US Surveyor's chain unit of measurement
        /// </summary>
        public static readonly Unit USChain = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsUSChain,
            Abbreviation = "us-ch",
            BaseConversionFactor = 20.11684023368047
        };

        /// <summary>
        /// A unit describing a US Surveyor's statute mile unit of measurement
        /// </summary>
        public static readonly Unit USStatuteMile = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsUSStatuteMile,
            Abbreviation = "us-mi",
            BaseConversionFactor = 1609.347218694437
        };

        #endregion US Linear

        #region Indian Linear

        /// <summary>
        /// A unit describing an Indian yard unit of measurement
        /// </summary>
        public static readonly Unit IndianYard = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsIndianYard,
            Abbreviation = "ind-yd",
            BaseConversionFactor = 0.91439523
        };

        /// <summary>
        /// A unit describing an Indian foot unit of measurement
        /// </summary>
        public static readonly Unit IndianFoot = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsIndianFoot,
            Abbreviation = "ind-ft",
            BaseConversionFactor = 0.30479841
        };

        /// <summary>
        /// A unit describing an Indian chain unit of measurement
        /// </summary>
        public static readonly Unit IndianChain = new Unit()
        {
            UnitType = UnitType.Linear,
            Name = Properties.Resources.UnitsIndianChain,
            Abbreviation = "ind-ch",
            BaseConversionFactor = 20.11669506
        };

        #endregion Indian Linear
    }
}